/*
 * Copyright 2007 Agile Plugins Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.agileplugins.monkey;

import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.event.DocumentEvent;
import com.intellij.openapi.editor.event.DocumentListener;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.MultiLineLabelUI;
import com.intellij.psi.PsiDirectory;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.psi.PsiElementFactory;
import com.intellij.psi.PsiPackage;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeCodeFragment;
import com.intellij.ui.EditorTextField;

import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

public class CreateComponentDialog extends DialogWrapper {
    private static final int MAX_PARAMS = 4;

    private Logger logger = Logger.getInstance(getClass().getName());
    private String message;
    private Project project;
    private PsiPackage psiPackage;
    private final PsiDirectory psidirectory;
    private EditorTextField interfaceField;
    private EditorTextField classField;
    private EditorTextField[] paramFields;
    private EditorTextField[] paramFieldNames;
    private PsiTypeCodeFragment[] typeCodeFragment;

    public CreateComponentDialog(Project project, PsiPackage psiPackage, PsiDirectory psidirectory) {
        super(project, false);
        this.project = project;
        this.psiPackage = psiPackage;
        this.psidirectory = psidirectory;
        setTitle("Create Component");
        this.message = "Create a component";
        setButtonsAlignment(0);
        init();
    }

    protected void doOKAction() {
        final Properties properties = getProperties();
        final Runnable runnable = new CreateComponentHandler(project, psidirectory, properties);
        CommandProcessor.getInstance().executeCommand(project,
                new Runnable() {
                    public void run() {
                        ApplicationManager.getApplication().runWriteAction(runnable);
                    }
                }, "Create Component", null);
    }

    public static String name() {
        return null;
    }

    public JComponent getPreferredFocusedComponent() {
        return interfaceField;
    }

    public Properties getProperties() {
        Properties properties = new Properties(FileTemplateManager.getInstance().getDefaultProperties());
        properties.setProperty("TEMPLATE_TYPE", interfaceField.getText().equals("Data") ? "Data" : "Component");
        properties.setProperty("PACKAGE_NAME", psiPackage.getQualifiedName());
        properties.setProperty("CLASS_NAME", classField.getText());
        properties.setProperty("INTERFACE_NAME", interfaceField.getText());
        properties.setProperty("INSTANCE_NAME", lcFirst(interfaceField.getText()));
        List params = new ArrayList();
        for (int i = 0; i < MAX_PARAMS; i++) {
            String fieldName = paramFieldNames[i].getText();
            PsiType type = getType(i);
            if (type == null) {
                params.add(new ParameterInfo(typeCodeFragment[i].getText(), fieldName));
            } else {
                params.add(new ParameterInfo(type, fieldName));
            }
        }
        PropertiesHelper.addFieldProperties("FIELD", properties, params, typeCodeFragment[0].getManager(), project);
        return properties;
    }

    protected Action[] createActions() {
        ArrayList arraylist = new ArrayList();
        arraylist.add(getOKAction());
        arraylist.add(getCancelAction());
        return (Action[]) arraylist.toArray(new Action[arraylist.size()]);
    }

    protected JComponent createNorthPanel() {
        JLabel jlabel = new JLabel(message);
        jlabel.setUI(new MultiLineLabelUI());
        JPanel jpanel = new JPanel(new BorderLayout());
        jpanel.add(jlabel, "North");
        jlabel.setIcon(UIManager.getIcon("OptionPane.questionIcon"));
        jlabel.setIconTextGap(10);
        jpanel.add(createOptionsPanel(), "Center");
        jpanel.add(Box.createVerticalStrut(7), "South");
        return jpanel;
    }

    protected JComponent createCenterPanel() {
        return null;
    }

    private JPanel createOptionsPanel() {
        GridBagConstraints c = new GridBagConstraints();
        JPanel panel = new JPanel(new GridBagLayout());
        panel.setMinimumSize(new Dimension(400, 0));
        c.insets = new Insets(5, 5, 5, 5);
        c.gridx = 0;
        c.gridy = 0;
        panel.add(new JLabel("Interface Name"), c);
        c.gridy = 1;
        panel.add(new JLabel("New Class Name"), c);
        for (int i = 0; i < MAX_PARAMS; i++) {
            c.gridy = i + 2;
            panel.add(new JLabel("Field " + (i + 1) + " Class"), c);
        }
        c.fill = GridBagConstraints.HORIZONTAL;
        c.weightx = 1.0;
        c.gridwidth = 2;
        c.gridx = 1;
        c.gridy = 0;
        panel.add(interfaceField = new EditorTextField(""), c);
        c.gridy = 1;
        panel.add(classField = new EditorTextField(""), c);
        c.gridwidth = 1;
        paramFields = new EditorTextField[MAX_PARAMS];
        paramFieldNames = new EditorTextField[MAX_PARAMS];
        typeCodeFragment = new PsiTypeCodeFragment[MAX_PARAMS];
        PsiElementFactory psielementfactory = psiPackage.getManager().getElementFactory();
        for (int i = 0; i < MAX_PARAMS; i++) {
            c.gridx = 1;
            c.gridy = i + 2;
            typeCodeFragment[i] = psielementfactory.createTypeCodeFragment(
                    "", psiPackage, false, true);
            Document document = PsiDocumentManager.getInstance(project).getDocument(typeCodeFragment[i]);
            final EditorTextField paramField = new EditorTextField(document, project, StdFileTypes.JAVA);
            panel.add(paramFields[i] = paramField, c);
            c.gridx = 2;
            final EditorTextField paramFieldName = new EditorTextField("");
            panel.add(paramFieldNames[i] = paramFieldName, c);
            paramFields[i].addDocumentListener(new DocumentListener() {

                public void beforeDocumentChange(DocumentEvent documentEvent) {
                }

                public void documentChanged(DocumentEvent documentEvent) {
                    paramFieldName.setText(lcFirst(paramField.getText()));
                }
            });
        }
        interfaceField.addDocumentListener(new DocumentListener() {

            public void beforeDocumentChange(DocumentEvent documentEvent) {
            }

            public void documentChanged(DocumentEvent documentEvent) {
                String text = interfaceField.getText();
                text = ("Data".equals(text)) ? "" : "Default" + text;
                classField.setText(text);
            }
        });
        return panel;
    }

    private String createGetter(String fieldName) {
        if (fieldName == null) {
            return null;
        }
        if (fieldName.length() == 0) {
            return "";
        }
        return "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }

    private String getPackage(PsiType type) {
        if (type == null) {
            return null;
        }
        String typeString = type.getCanonicalText();
        int endIndex = typeString.lastIndexOf('.');
        return endIndex == -1 ? "" : typeString.substring(0, endIndex);
    }

    private PsiType getType(int i) {
        try {
            return typeCodeFragment[i].getType();
        } catch (Exception e) {
            return null;
        }
    }

    private String lcFirst(String text) {
        if (text == null) {
            return null;
        }
        if (text.endsWith("[]")) {
            text = text.substring(0, text.length() - 2) + "s";
        }
        if (text.length() == 0) {
            return "";
        }
        if (text.charAt(0) >= 'a' && text.charAt(0) <= 'z') {
            return text + "Value";
        }
        return text.substring(0, 1).toLowerCase() + text.substring(1);
    }
}

